/**
 * Copyright 2018 asiainfo Inc.
 **/
package com.myz.rabbitmq.order.producer;

import com.myz.rabbitmq.common.config.RabbitMqConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.UUID;

/**
 * 在spring boot默认会生成AmqpAdmin和AmqpTemplate 供我们和RabbitMQ交互。
 * AmqpTemplate 的默认实例是RabbitTemplate，AmqpAdmin 默认实例是RabbitAdmin，通过源码发现其内部实现实际是RabbitTemplate。所以AmqpAdmin和AmqpTemplate两者本质是相同的
 *
 * @author maoyz on 2018/8/29
 * @version v1.0
 */
@Component
@Slf4j
public class RabbitProducer {

    @Resource
    private RabbitTemplate rabbitTemplate;

    // 此接口默认实现只有一个，且是RabbitAdmin，通过源码发现其内部实现实际是RabbitTemplate。所以AmqpAdmin和AmqpTemplate当前两者本质是相同的
    @Resource
    private AmqpAdmin amqpAdmin;

    // 此接口的默认实现是RabbitTemplate，目前只有一个实现，
    @Resource
    private AmqpTemplate amqpTemplate;

    @Resource
    private RabbitTemplate.ConfirmCallback confirmCallback;

    @Resource
    private RabbitTemplate.ReturnCallback returnCallback;

    public void sendMsg(String json) {
        String msgId = UUID.randomUUID().toString();

        log.debug("msgId: {}", msgId);

        /*
         * 构建Message ,主要是使用 msgId 将 message 和 CorrelationData 关联起来。
         * 这样当消息发送到交换机失败的时候，在 MsgSendConfirmCallBack 中就可以根据
         * correlationData.getId()即 msgId,知道具体是哪个message发送失败,进而进行处理。
         * 将 msgId和 message绑定
         */
        Message message = MessageBuilder.withBody(json.getBytes())
                .setContentType(MessageProperties.CONTENT_TYPE_JSON)
                .setCorrelationId(msgId)
                .build();


        /**
         * 转换并发送消息。 将参数对象转换为org.springframework.amqp.core.Message后发送
         * exchange:交换机名称
         * outingKey:路由关键字
         * object:发送的消息内容
         * correlationData:消息ID
         */
        // 转换并发送消息,且等待消息者返回响应消息。
        String receive = String.valueOf(rabbitTemplate.convertSendAndReceive(RabbitMqConstant.ExchangeEnum.CONTRACT_DIRECT.getCode(),
                RabbitMqConstant.RoutingKeyEnum.DIRECT_QUEUE_KEY.getCode(), message, new CorrelationData(msgId)));

        log.info("生产消息已send ...，执行后续工作--> {}", receive);
    }

    public void sendMsgVoid(String msg) {
        String msgId = UUID.randomUUID().toString();
        log.debug("msgId: {}", msgId);
        /*
         * 构建Message ,主要是使用 msgId 将 message 和 CorrelationData 关联起来。
         * 这样当消息发送到交换机失败的时候，在 MsgSendConfirmCallBack 中就可以根据
         * correlationData.getId()即 msgId,知道具体是哪个message发送失败,进而进行处理。
         * 将 msgId和 message绑定
         */
        Message message = MessageBuilder.withBody(msg.getBytes())
                .setContentType(MessageProperties.CONTENT_TYPE_JSON)
                .setCorrelationId(msgId)
                .build();

        /**
         * 转换并发送消息。 将参数对象转换为org.springframework.amqp.core.Message后发送
         * exchange:交换机名称
         * outingKey:路由关键字
         * object:发送的消息内容
         * correlationData:消息ID
         */

        /**
         * 确保消息发送失败后可以重新返回到队列中
         * 注意：yml需要配置 publisher-returns: true
         */
        rabbitTemplate.setMandatory(true);
        rabbitTemplate.setReturnCallback(returnCallback);
        rabbitTemplate.setConfirmCallback(confirmCallback);
        rabbitTemplate.convertAndSend(RabbitMqConstant.ExchangeEnum.CONTRACT_DIRECT.getCode(),
                "queue_one_key", message, new CorrelationData(msgId));
    }
}
